import { ComponentInternalInstance, getCurrentInstance, onUnmounted } from 'vue'
import { Emitter, EventNameType, EventCallback, ListenStopHandle } from './emitter';

const emitter = new Emitter()
// 对eventMap的弱引用
const eventMap = new WeakMap<ComponentInternalInstance, Array<ListenStopHandle>>()
// 对为vm的去重弱引用
const markOnUnmounted = new WeakSet<ComponentInternalInstance>()

const markListenHandle = (stopHandle: ListenStopHandle) => {
  // get vue instance
  let vm: ComponentInternalInstance | null = getCurrentInstance()
  if (vm === null) {
    // error. please call '$on/$once' on setup or Lifecycle Hooks
    return
  }

  // 1.如果eventMap中有当前组件的实例(vm), 则取他的map值
  // 2.如果eventMap中没有当前组件的实例(vm), 则给他设置值, 并取值(链式操作)
  const list = eventMap.get(vm) || eventMap.set(vm, []).get(vm)

  list?.push(stopHandle)

  // 如果markOnUnmounted中不包含vm
  if (!markOnUnmounted.has(vm)) {
    markOnUnmounted.add(vm)
    // 设置onUnmounted的this指向为vm
    onUnmounted(() => {
      // 如果有vm, 则获取vm的eventMap值
      const stopHandleList = vm && eventMap.get(vm)
      // 这一步没看懂, 为什么要执行一遍订阅函数？
      stopHandleList?.forEach(val => val())
      vm = null
    }, vm)
  }
}

export const $_on = (type: EventNameType, callback: EventCallback): ListenStopHandle => {
  const stopHandle = emitter.on(type, callback)
  markListenHandle(stopHandle)
  return stopHandle
}

export const $_once = (type: EventNameType, callback: EventCallback): ListenStopHandle => {
  const stopHandle = emitter.once(type, callback)
  markListenHandle(stopHandle)
  return stopHandle
}

export const $_off = emitter.off
export const $_emit = emitter.emit
